package cn.daniellee.plugin.pm.listener;

import cn.daniellee.plugin.pm.PartnerMission;
import cn.daniellee.plugin.pm.component.ItemGenerator;
import cn.daniellee.plugin.pm.core.MissionCore;
import cn.daniellee.plugin.pm.model.Mission;
import cn.daniellee.plugin.pm.model.MissionItem;
import cn.daniellee.plugin.pm.model.Online;
import cn.daniellee.plugin.pm.model.PlayerData;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.block.data.Ageable;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.*;

import java.util.*;

public class PlayerListener implements Listener {

	@EventHandler
	public void onPlayerChat(AsyncPlayerChatEvent e) {
		Player player = e.getPlayer();
		Object operation = MissionCore.editOperation.get(player.getName());
		if (operation != null) {
			PlayerData playerData = PartnerMission.getInstance().getStorage().getPlayerByName(player.getName());
			if (operation instanceof String) {
				e.setCancelled(true);
				MissionCore.editOperation.remove(player.getName());
				if ("cancel".equalsIgnoreCase(e.getMessage())) {
					player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.edit-canceled", "&eThe edit operation has been canceled.")).replace("&", "§"));
				} else {
					String contact = e.getMessage();
					playerData.setContact(contact);
					Map<String, Object> fields = new HashMap<>();
					fields.put("contact", contact);
					PartnerMission.getInstance().getStorage().updatePlayer(player.getName(), fields);
					player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.contact-modify", "&eContact information modified successfully.")).replace("&", "§"));
				}
			} else if (operation instanceof List) {
				e.setCancelled(true);
				List<String> intro = (List<String>) operation;
				if (e.getMessage().startsWith("add ") || e.getMessage().startsWith("ADD ")) {
					int maxLine = PartnerMission.getInstance().getConfig().getInt("setting.intro-max-line", 10);
					if (intro.size() < maxLine) {
						intro.add(e.getMessage().substring(4));
						showIntroduction(e.getPlayer(), intro);
					} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.reach-max", "&eMaximum number of rows has been reached and cannot be added.")).replace("&", "§"));
				} else if ((e.getMessage().startsWith("set ") || e.getMessage().startsWith("SET "))) {
					String[] split = e.getMessage().split(" ");
					if (split.length > 2 && split[1].matches("^\\d+$")) {
						int line = Integer.parseInt(split[1]);
						if (line > 0 && intro.size() >= line) {
							intro.set(line - 1, StringUtils.join(Arrays.copyOfRange(split, 2, split.length), " "));
							showIntroduction(e.getPlayer(), intro);
						} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.incorrect-line", "&eIncorrect line number, please check and resend.")).replace("&", "§"));
					} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.incorrect-format", "&eIncorrect format, please check and resend.")).replace("&", "§"));
				} else if (e.getMessage().startsWith("del ") || e.getMessage().startsWith("DEL ")) {
					String[] split = e.getMessage().split(" ");
					if (split.length > 1 && split[1].matches("^\\d+$")) {
						int line = Integer.parseInt(split[1]);
						if (line > 0 && intro.size() >= line) {
							intro.remove(line - 1);
							showIntroduction(e.getPlayer(), intro);
						} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.incorrect-line", "&eIncorrect line number, please check and resend.")).replace("&", "§"));
					} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.incorrect-format", "&eIncorrect format, please check and resend.")).replace("&", "§"));
				} else if ("ok".equalsIgnoreCase(e.getMessage())) {
					MissionCore.editOperation.remove(player.getName());
					Map<String, Object> fields = new HashMap<>();
					fields.put("introduction", new Gson().toJson(intro));
					PartnerMission.getInstance().getStorage().updatePlayer(player.getName(), fields);
					player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.intro-modify", "&eSelf introduction successfully revised.")).replace("&", "§"));
				} else player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.incorrect-format", "&eIncorrect format, please check and resend.")).replace("&", "§"));
			}
		}
	}

	private void showIntroduction(Player player, List<String> introduction) {
		player.sendMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.intro-show", "&eEdited successfully, the current introduction is:")).replace("&", "§"));
		for (int i = 0; i < introduction.size(); i++) player.sendMessage(("&e" + (i + 1) + ". &r" + introduction.get(i)).replace("&", "§"));
		player.sendMessage(PartnerMission.getInstance().getConfig().getString("message.intro-tips", "&e(&badd [content] &eto add a line, &bset [line] [content] &eto modify a line, &bdel [line] &eto delete a line, &bok &eto complete)").replace("&", "§"));
	}

	@EventHandler
	public void onPlayerBlockBreak(BlockBreakEvent e) {
		Player player = e.getPlayer();
		Mission mission = MissionCore.getPlayerActiveMission(player.getName());
		if (mission != null) {
			if (mission.getProgress() == 0) {
				MissionItem missionItem = MissionCore.felling.get(mission.getFellingIndex());
				if (missionItem.getType().stream().anyMatch(item -> item == e.getBlock().getType()) && MissionCore.checkResidencePerm(player, e.getBlock()) && mission.excavated.stream().noneMatch(item -> item.equals(e.getBlock().getLocation()))) {
					mission.setFellingCurrent(mission.getFellingCurrent() + 1);
					if (mission.getFellingCurrent() >= missionItem.getTarget()) {
						mission.setProgress(1);
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.next-mission", "&eThe current mission has been completed, open the menu to view the next.")).replace("&", "§"));
					} else {
						mission.excavated.add(e.getBlock().getLocation());
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.show-progress", "&eProgress: &b{current}/{target}").replace("{current}", Integer.toString(mission.getFellingCurrent())).replace("{target}", Integer.toString(missionItem.getTarget()))).replace("&", "§"));
					}
				}
			} else if (mission.getProgress() == 1) {
				MissionItem missionItem = MissionCore.mining.get(mission.getMiningIndex());
				if (missionItem.getType().stream().anyMatch(item -> item == e.getBlock().getType()) && MissionCore.checkResidencePerm(player, e.getBlock()) && mission.excavated.stream().noneMatch(item -> item.equals(e.getBlock().getLocation()))) {
					mission.setMiningCurrent(mission.getMiningCurrent() + 1);
					if (mission.getMiningCurrent() >= missionItem.getTarget()) {
						mission.setProgress(2);
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.next-mission", "&eThe current mission has been completed, open the menu to view the next.")).replace("&", "§"));
					} else {
						mission.excavated.add(e.getBlock().getLocation());
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.show-progress", "&eProgress: &b{current}/{target}").replace("{current}", Integer.toString(mission.getMiningCurrent())).replace("{target}", Integer.toString(missionItem.getTarget()))).replace("&", "§"));
					}
				}
			} else if (mission.getProgress() == 4) {
				MissionItem missionItem = MissionCore.gatherCrop.get(mission.getGatherCropIndex());
				if (missionItem.getType().stream().anyMatch(item -> item == e.getBlock().getType()) && MissionCore.checkResidencePerm(player, e.getBlock()) && mission.excavated.stream().noneMatch(item -> item.equals(e.getBlock().getLocation()))) {
					// 如果是未成熟的不计数
					if (e.getBlock().getBlockData() instanceof Ageable block && block.getAge() != block.getMaximumAge()) return;
					mission.setGatherCropCurrent(mission.getGatherCropCurrent() + 1);
					if (mission.getGatherCropCurrent() >= missionItem.getTarget()) {
						mission.setProgress(5);
						MissionCore.completeMission(mission);
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.all-complete", "&eAll tasks have been completed! Open the menu to claim rewards!")).replace("&", "§"));
						if (PartnerMission.getInstance().isCompleteBoardCast()) Bukkit.broadcastMessage((PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.boardcast.complete", "&e{inviter} &eand &b{invitee} &ehave completed their mission!").replace("{inviter}", mission.getInviter()).replace("{invitee}", mission.getInvitee())).replace("&", "§"));
					} else {
						mission.excavated.add(e.getBlock().getLocation());
						MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.show-progress", "&eProgress: &b{current}/{target}").replace("{current}", Integer.toString(mission.getGatherCropCurrent())).replace("{target}", Integer.toString(missionItem.getTarget()))).replace("&", "§"));
					}
				}
			}
		}
	}

	@EventHandler
	public void onPlayerKillEntity(EntityDamageByEntityEvent e) {
		if (e.getEntity() instanceof Damageable entity && e.getDamager() instanceof Player player) {
			if (entity.getHealth() < e.getFinalDamage()) {
				Mission mission = MissionCore.getPlayerActiveMission(player.getName());
				if (mission != null) {
					if (mission.getProgress() == 2) {
						MissionItem missionItem = MissionCore.killMonster.get(mission.getKillMonsterIndex());
						if (missionItem.getType().stream().anyMatch(item -> item == e.getEntityType())) {
							mission.setKillMonsterCurrent(mission.getKillMonsterCurrent() + 1);
							if (mission.getKillMonsterCurrent() >= missionItem.getTarget()) {
								mission.setProgress(3);
								MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.next-mission", "&eThe current mission has been completed, open the menu to view the next.")).replace("&", "§"));
							} else MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.show-progress", "&eProgress: &b{current}/{target}").replace("{current}", Integer.toString(mission.getKillMonsterCurrent())).replace("{target}", Integer.toString(missionItem.getTarget()))).replace("&", "§"));
						}
					} else if (mission.getProgress() == 3) {
						MissionItem missionItem = MissionCore.killAnimal.get(mission.getKillAnimalIndex());
						if (missionItem.getType().stream().anyMatch(item -> item == e.getEntityType())) {
							mission.setKillAnimalCurrent(mission.getKillAnimalCurrent() + 1);
							if (mission.getKillAnimalCurrent() >= missionItem.getTarget()) {
								mission.setProgress(4);
								MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.next-mission", "&eThe current mission has been completed, open the menu to view the next.")).replace("&", "§"));
							} else MissionCore.sendMessageBoth(mission, (PartnerMission.getInstance().getPrefix() + PartnerMission.getInstance().getConfig().getString("message.show-progress", "&eProgress: &b{current}/{target}").replace("{current}", Integer.toString(mission.getKillAnimalCurrent())).replace("{target}", Integer.toString(missionItem.getTarget()))).replace("&", "§"));
						}
					}
				}
			}
		}
	}

	@EventHandler
	public void onPlayerLogin(PlayerLoginEvent e) {
		PlayerData playerData = PartnerMission.getInstance().getStorage().getPlayerByName(e.getPlayer().getName());
		MissionCore.onlines.add(new Online(playerData.getName(), playerData.getOnlineMinutes()));
		Bukkit.getScheduler().runTaskAsynchronously(PartnerMission.getInstance(), () -> {
			String texture = ItemGenerator.getPlayerTexture(playerData.getName());
			if (texture != null) {
				Map<String, Object> fields = new HashMap<>();
				fields.put("texture", texture);
				PartnerMission.getInstance().getStorage().updatePlayer(playerData.getName(), fields);
			}
		});
	}

	@EventHandler
	public void onPlayerQuit(PlayerQuitEvent e) {
		Player player = e.getPlayer();
		MissionCore.onlines.removeIf(item -> item.getName().equals(player.getName()));
		MissionCore.editOperation.remove(player.getName());
	}

}
